/*
 * Copyright 2011 Mark Davidson.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.dctmcommons.impl;

import java.util.ArrayList;
import java.util.List;

import org.dctmcommons.IParamCheck;
import org.dctmcommons.IQueryHelper;
import org.dctmcommons.ITypeHelper;
import org.dctmcommons.ITypedObjectCallback;

import com.documentum.fc.client.IDfQuery;
import com.documentum.fc.client.IDfSession;
import com.documentum.fc.client.IDfTypedObject;
import com.documentum.fc.common.DfException;

/**
 * Type-related helper methods.
 */
public class TypeHelper implements ITypeHelper {

	/** DQL for identifying descendant types. */
	private static final String DQL_DESCENDANT_TYPES =
		"select r_type_name from dmi_type_info " +
		"where any r_supertype = 'PARENT' order by r_type_name";
	
	/** DQL for identifying ancestor types. */
	private static final String DQL_ANCESTOR_TYPES =
		"select r_supertype from dmi_type_info " +
		"where r_type_name = 'CHILD' order by r_supertype";

	/** The query helper instance. */
	private static final IQueryHelper queryHelper = QueryHelper.getInstance();
	
	/** The parameter check instance. */
	private static final IParamCheck paramCheck = ParamCheck.getInstance();
	
	/**
	 * The default constructor.
	 */
	private TypeHelper(){}
	
	/**
	 * Factory method.
	 * @return The type helper instance
	 */
	public static ITypeHelper getInstance() {
		return new TypeHelper();
	}
		
	/* (non-Javadoc)
	 * @see org.dctmcommons.impl.ITypeHelper#getDescendantTypes(com.documentum.fc.client.IDfSession, java.lang.String, boolean)
	 */
	@Override
	public String[] getDescendantTypes(final IDfSession session,
									   final String type,
									   final boolean includeSelf)
		throws DfException {
		return getRelatedTypes(session, type, true, includeSelf);
	}

	/* (non-Javadoc)
	 * @see org.dctmcommons.impl.ITypeHelper#isDescendantType(com.documentum.fc.client.IDfSession, java.lang.String, java.lang.String)
	 */
	@Override
	public boolean isDescendantType(final IDfSession session,
									final String parentType,
									final String childType)
		throws DfException {
		
		paramCheck.checkObject(session, "session");
		paramCheck.checkString(parentType, "parentType");
		paramCheck.checkString(childType, "childType");
		
		boolean isDescendant = false;
		final String[] ancestors = getAncestorTypes(session, childType, false);
		
		if (ancestors != null) {
			for (final String ancestor : ancestors) {
				if (ancestor.equals(parentType)) {
					isDescendant = true;
					break;
				}
			}
		}
		return isDescendant;
	}
	
	/* (non-Javadoc)
	 * @see org.dctmcommons.impl.ITypeHelper#getAncestorTypes(com.documentum.fc.client.IDfSession, java.lang.String, boolean)
	 */
	@Override
	public String[] getAncestorTypes(final IDfSession session,
									 final String type,
									 final boolean includeSelf)
		throws DfException {
		return getRelatedTypes(session, type, false, includeSelf);
	}

	/* (non-Javadoc)
	 * @see org.dctmcommons.impl.ITypeHelper#getRelatedTypes(com.documentum.fc.client.IDfSession, java.lang.String, boolean, boolean)
	 */
	@Override
	public String[] getRelatedTypes(final IDfSession session,
								    final String type,
								    final boolean descendantTypes,
								    final boolean includeSelf)
		throws DfException {
		
		paramCheck.checkObject(session, "session");
		paramCheck.checkObject(type, "type");
		
		String dql = null;
		final StringBuilder sb = new StringBuilder();
		
		if (descendantTypes) {
			dql = DQL_DESCENDANT_TYPES.replaceAll("PARENT", type);
			sb.append("r_type_name");
		} else {
			dql = DQL_ANCESTOR_TYPES.replaceAll("CHILD", type);
			sb.append("r_supertype");
		}
		
		final String attribName = sb.toString();
		final List<String> types = new ArrayList<String>();
		
		queryHelper.query(session,
						  dql,
						  IDfQuery.DF_READ_QUERY,
						  new ITypedObjectCallback() {
			
			@Override
			public boolean read(IDfTypedObject typedObject) throws DfException {
				final String typeName = typedObject.getString(attribName);
				if (!typeName.equals(type) ||
					(typeName.equals(type) && includeSelf)) {
					types.add(typeName);
				}
				return true;
			}
		});
		
		if (types.size() == 0) {
			return null;
		} else {
			return types.toArray(new String[] {});
		}
	}

}
